libxl: support mapping files rather than carrying paths around
authorIan Jackson <Ian.Jackson@eu.citrix.com>
Wed, 14 Jul 2010 15:43:49 +0000 (16:43 +0100)
committerIan Jackson <Ian.Jackson@eu.citrix.com>
Wed, 14 Jul 2010 15:43:49 +0000 (16:43 +0100)
This will allow us to map and then unlink the file and therefore
delete the process on process exit or explicit unmap.

Using the mmaped versions of these files required rewriting build_pv
to use the xc_dom builder functionality directly rather than through
the xc_linux_build "compatibility layer". (The status of the
xc_linux_build interface as a compatibility layer seems a bit dubious
since all existing callers use it but if anything is going to replace
it then libxl seems like the likely candidate).

I'm not thrilled with the definition of the maps lifecycle. This could
be solved by adding a helper function to explicitly free the toplevel
structure.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
tools/libxl/libxl.c
tools/libxl/libxl.h
tools/libxl/libxl_dom.c
tools/libxl/xl_cmdimpl.c
tools/ocaml/libs/xl/xl_stubs.c

index 687a20e1067383df94cf79b28f23baa69bf1b4ac..bd39454ca7ab642cc1abc06f3ba8fdd3e8f953e8 100644 (file)
@@ -22,6 +22,7 @@
 #include <sys/types.h>
 #include <fcntl.h>
 #include <sys/select.h>
+#include <sys/mman.h>
 #include <sys/wait.h>
 #include <signal.h>
 #include <unistd.h> /* for write, unlink and close */
@@ -291,12 +292,12 @@ int libxl_domain_build(struct libxl_ctx *ctx, libxl_domain_build_info *info, uin
         vments[i++] = "image/ostype";
         vments[i++] = "linux";
         vments[i++] = "image/kernel";
-        vments[i++] = (char*) info->kernel;
+        vments[i++] = (char*) info->kernel.path;
         vments[i++] = "start_time";
         vments[i++] = libxl_sprintf(ctx, "%lu.%02d", start_time.tv_sec,(int)start_time.tv_usec/10000);
-        if (info->u.pv.ramdisk) {
+        if (info->u.pv.ramdisk.path) {
             vments[i++] = "image/ramdisk";
-            vments[i++] = (char*) info->u.pv.ramdisk;
+            vments[i++] = (char*) info->u.pv.ramdisk.path;
         }
         if (info->u.pv.cmdline) {
             vments[i++] = "image/cmdline";
@@ -305,6 +306,10 @@ int libxl_domain_build(struct libxl_ctx *ctx, libxl_domain_build_info *info, uin
     }
     ret = build_post(ctx, domid, info, state, vments, localents);
 out:
+    libxl_file_reference_unmap(ctx, &info->kernel);
+    if (!info->hvm)
+           libxl_file_reference_unmap(ctx, &info->u.pv.ramdisk);
+
     return ret;
 }
 
@@ -338,12 +343,12 @@ int libxl_domain_restore(struct libxl_ctx *ctx, libxl_domain_build_info *info,
         vments[i++] = "image/ostype";
         vments[i++] = "linux";
         vments[i++] = "image/kernel";
-        vments[i++] = (char*) info->kernel;
+        vments[i++] = (char*) info->kernel.path;
         vments[i++] = "start_time";
         vments[i++] = libxl_sprintf(ctx, "%lu.%02d", start_time.tv_sec,(int)start_time.tv_usec/10000);
-        if (info->u.pv.ramdisk) {
+        if (info->u.pv.ramdisk.path) {
             vments[i++] = "image/ramdisk";
-            vments[i++] = (char*) info->u.pv.ramdisk;
+            vments[i++] = (char*) info->u.pv.ramdisk.path;
         }
         if (info->u.pv.cmdline) {
             vments[i++] = "image/cmdline";
@@ -361,6 +366,10 @@ int libxl_domain_restore(struct libxl_ctx *ctx, libxl_domain_build_info *info,
     }
 
 out:
+    libxl_file_reference_unmap(ctx, &info->kernel);
+    if (!info->hvm)
+           libxl_file_reference_unmap(ctx, &info->u.pv.ramdisk);
+
     esave = errno;
 
     flags = fcntl(fd, F_GETFL);
@@ -1057,9 +1066,9 @@ static int libxl_create_stubdom(struct libxl_ctx *ctx,
     b_info.max_vcpus = 1;
     b_info.max_memkb = 32 * 1024;
     b_info.target_memkb = b_info.max_memkb;
-    b_info.kernel = libxl_abs_path(ctx, "ioemu-stubdom.gz", libxl_xenfirmwaredir_path());
+    b_info.kernel.path = libxl_abs_path(ctx, "ioemu-stubdom.gz", libxl_xenfirmwaredir_path());
     b_info.u.pv.cmdline = libxl_sprintf(ctx, " -d %d", info->domid);
-    b_info.u.pv.ramdisk = "";
+    b_info.u.pv.ramdisk.path = "";
     b_info.u.pv.features = "";
     b_info.hvm = 0;
 
@@ -3181,3 +3190,47 @@ int libxl_tmem_shared_auth(struct libxl_ctx *ctx, uint32_t domid,
     return rc;
 }
 
+int libxl_file_reference_map(struct libxl_ctx *ctx, libxl_file_reference *f)
+{
+       struct stat st_buf;
+       int ret, fd;
+       void *data;
+
+       if (f->mapped)
+               return 0;
+
+       fd = open(f->path, O_RDONLY);
+       if (f < 0)
+               return ERROR_FAIL;
+
+       ret = fstat(fd, &st_buf);
+       if (ret < 0)
+               goto out;
+
+       ret = -1;
+       data = mmap(NULL, st_buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+       if (data == NULL)
+               goto out;
+
+       f->mapped = 1;
+       f->data = data;
+       f->size = st_buf.st_size;
+
+       ret = 0;
+out:
+       close(fd);
+
+       return ret == 0 ? 0 : ERROR_FAIL;
+}
+
+int libxl_file_reference_unmap(struct libxl_ctx *ctx, libxl_file_reference *f)
+{
+       int ret;
+
+       if (!f->mapped)
+               return 0;
+
+       ret = munmap(f->data, f->size);
+
+       return ret == 0 ? 0 : ERROR_FAIL;
+}
index 67ca8a751dcc0a303439c94fd9651c9da921ea9d..e58e9a5238ed5415fbc107ebaaa5a854313f4798 100644 (file)
@@ -89,6 +89,24 @@ typedef struct {
     char *poolname;
 } libxl_domain_create_info;
 
+typedef struct {
+    /*
+     * Path is always set if the file refernece is valid. However if
+     * mapped is true then the actual file may already be unlinked.
+     */
+    char *path;
+    int mapped;
+    void *data;
+    size_t size;
+} libxl_file_reference;
+
+/*
+ * Instances of libxl_file_reference contained in this struct which
+ * have been mapped (with libxl_file_reference_map) will be unmapped
+ * by libxl_domain_build/restore. If either of these are never called
+ * then the user is responsible for calling
+ * libxl_file_reference_unmap.
+ */
 typedef struct {
     int max_vcpus;
     int cur_vcpus;
@@ -98,7 +116,7 @@ typedef struct {
     uint32_t video_memkb;
     uint32_t shadow_memkb;
     bool disable_migrate;
-    const char *kernel;
+    libxl_file_reference kernel;
     int hvm;
     union {
         struct {
@@ -115,7 +133,7 @@ typedef struct {
         struct {
             uint32_t   slack_memkb;
             const char *cmdline;
-            const char *ramdisk;
+            libxl_file_reference ramdisk;
             const char *features;
         } pv;
     } u;
@@ -308,6 +326,9 @@ int libxl_domain_resume(struct libxl_ctx *ctx, uint32_t domid);
 int libxl_domain_shutdown(struct libxl_ctx *ctx, uint32_t domid, int req);
 int libxl_domain_destroy(struct libxl_ctx *ctx, uint32_t domid, int force);
 
+int libxl_file_reference_map(struct libxl_ctx *ctx, libxl_file_reference *f);
+int libxl_file_reference_unmap(struct libxl_ctx *ctx, libxl_file_reference *f);
+
 char *libxl_uuid2string(struct libxl_ctx *ctx, uint8_t uuid[16]);
   /* 0 means ERROR_ENOMEM, which we have logged */
 
index 787d6c7a32c73b467bf0dfb3c632b8f3afc97511..3b398cb5dbb2e2c53ba02702ce84e0d283c5ab31 100644 (file)
@@ -143,22 +143,76 @@ int build_pv(struct libxl_ctx *ctx, uint32_t domid,
     int ret;
     int flags = 0;
 
+    xc_dom_loginit(ctx->xch);
+
     dom = xc_dom_allocate(ctx->xch, info->u.pv.cmdline, info->u.pv.features);
     if (!dom) {
         XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xc_dom_allocate failed");
-        return -1;
+        return ERROR_FAIL;
+    }
+
+    if (info->kernel.mapped) {
+        if ( (ret = xc_dom_kernel_mem(dom, info->kernel.data, info->kernel.size)) != 0) {
+            XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xc_dom_kernel_mem failed");
+            goto out;
+        }
+    } else {
+        if ( (ret = xc_dom_kernel_file(dom, info->kernel.path)) != 0) {
+            XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xc_dom_kernel_file failed");
+            goto out;
+        }
     }
-    ret = xc_dom_linux_build(ctx->xch, dom, domid, info->target_memkb / 1024,
-                                  info->kernel, info->u.pv.ramdisk, flags,
-                                  state->store_port, &state->store_mfn,
-                                  state->console_port, &state->console_mfn);
-    if (ret != 0) {
-        xc_dom_release(dom);
-        XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, ret, "xc_dom_linux_build failed");
-        return -2;
+
+    if ( info->u.pv.ramdisk.path && strlen(info->u.pv.ramdisk.path) ) {
+        if (info->u.pv.ramdisk.mapped) {
+            if ( (ret = xc_dom_ramdisk_mem(dom, info->u.pv.ramdisk.data, info->u.pv.ramdisk.size)) != 0 ) {
+                XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xc_dom_ramdisk_mem failed");
+                goto out;
+            }
+        } else {
+            if ( (ret = xc_dom_ramdisk_file(dom, info->u.pv.ramdisk.path)) != 0 ) {
+                XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xc_dom_ramdisk_file failed");
+                goto out;
+            }
+        }
     }
+
+    dom->flags = flags;
+    dom->console_evtchn = state->console_port;
+    dom->xenstore_evtchn = state->store_port;
+
+    if ( (ret = xc_dom_boot_xen_init(dom, ctx->xch, domid)) != 0 ) {
+        XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xc_dom_boot_xen_init failed");
+        goto out;
+    }
+    if ( (ret = xc_dom_parse_image(dom)) != 0 ) {
+        XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xc_dom_parse_image failed");
+        goto out;
+    }
+    if ( (ret = xc_dom_mem_init(dom, info->target_memkb / 1024)) != 0 ) {
+        XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xc_dom_mem_init failed");
+        goto out;
+    }
+    if ( (ret = xc_dom_boot_mem_init(dom)) != 0 ) {
+        XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xc_dom_boot_mem_init failed");
+        goto out;
+    }
+    if ( (ret = xc_dom_build_image(dom)) != 0 ) {
+        XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xc_dom_build_image failed");
+        goto out;
+    }
+    if ( (ret = xc_dom_boot_image(dom)) != 0 ) {
+        XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xc_dom_boot_image failed");
+        goto out;
+    }
+
+    state->console_mfn = xc_dom_p2m_host(dom, dom->console_pfn);
+    state->store_mfn = xc_dom_p2m_host(dom, dom->xenstore_pfn);
+
+    ret = 0;
+out:
     xc_dom_release(dom);
-    return 0;
+    return ret == 0 ? 0 : ERROR_FAIL;
 }
 
 int build_hvm(struct libxl_ctx *ctx, uint32_t domid,
@@ -166,12 +220,17 @@ int build_hvm(struct libxl_ctx *ctx, uint32_t domid,
 {
     int ret;
 
+    if (info->kernel.mapped) {
+        XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "build_hvm kernel cannot be mmapped");
+        return ERROR_INVAL;
+    }
+
     ret = xc_hvm_build_target_mem(
         ctx->xch,
         domid,
         (info->max_memkb - info->video_memkb) / 1024,
         (info->target_memkb - info->video_memkb) / 1024,
-        libxl_abs_path(ctx, (char *)info->kernel,
+        libxl_abs_path(ctx, (char *)info->kernel.path,
                        libxl_xenfirmwaredir_path()));
     if (ret) {
         XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, ret, "hvm building failed");
index 090e36971288ee3d19b2308e7c514d8d52b4e8cf..c355505ae56f022c860024e8fda70e5cc6789186 100644 (file)
@@ -196,7 +196,7 @@ static void init_build_info(libxl_domain_build_info *b_info, libxl_domain_create
     if (c_info->hvm) {
         b_info->shadow_memkb = 0; /* Set later */
         b_info->video_memkb = 8 * 1024;
-        b_info->kernel = "hvmloader";
+        b_info->kernel.path = "hvmloader";
         b_info->hvm = 1;
         b_info->u.hvm.pae = 1;
         b_info->u.hvm.apic = 1;
@@ -366,7 +366,7 @@ static void printf_info(int domid,
     printf("\t(image\n");
     if (c_info->hvm) {
         printf("\t\t(hvm\n");
-        printf("\t\t\t(loader %s)\n", b_info->kernel);
+        printf("\t\t\t(loader %s)\n", b_info->kernel.path);
         printf("\t\t\t(video_memkb %d)\n", b_info->video_memkb);
         printf("\t\t\t(shadow_memkb %d)\n", b_info->shadow_memkb);
         printf("\t\t\t(pae %d)\n", b_info->u.hvm.pae);
@@ -397,9 +397,9 @@ static void printf_info(int domid,
         printf("\t\t)\n");
     } else {
         printf("\t\t(linux %d)\n", b_info->hvm);
-        printf("\t\t\t(kernel %s)\n", b_info->kernel);
+        printf("\t\t\t(kernel %s)\n", b_info->kernel.path);
         printf("\t\t\t(cmdline %s)\n", b_info->u.pv.cmdline);
-        printf("\t\t\t(ramdisk %s)\n", b_info->u.pv.ramdisk);
+        printf("\t\t\t(ramdisk %s)\n", b_info->u.pv.ramdisk.path);
         printf("\t\t)\n");
     }
     printf("\t)\n");
@@ -563,7 +563,7 @@ static void parse_config_data(const char *configfile_filename_report,
         b_info->video_memkb = l * 1024;
 
     if (!xlu_cfg_get_string (config, "kernel", &buf))
-        b_info->kernel = strdup(buf);
+        b_info->kernel.path = strdup(buf);
 
     if (c_info->hvm == 1) {
         if (!xlu_cfg_get_long (config, "pae", &l))
@@ -603,7 +603,7 @@ static void parse_config_data(const char *configfile_filename_report,
 
         b_info->u.pv.cmdline = cmdline;
         if (!xlu_cfg_get_string (config, "ramdisk", &buf))
-            b_info->u.pv.ramdisk = strdup(buf);
+            b_info->u.pv.ramdisk.path = strdup(buf);
     }
 
     if (!xlu_cfg_get_list (config, "disk", &vbds, 0)) {
index 4e8d45ea2e2e30a275d651f462cdabd24f42d470..0f523ee2d477996572813b9608755aac6f944b25 100644 (file)
@@ -120,7 +120,7 @@ static int domain_build_info_val (libxl_domain_build_info *c_val, value v)
        c_val->target_memkb = Int64_val(Field(v, 3));
        c_val->video_memkb = Int64_val(Field(v, 4));
        c_val->shadow_memkb = Int64_val(Field(v, 5));
-       c_val->kernel = String_val(Field(v, 6));
+       c_val->kernel.path = String_val(Field(v, 6));
        c_val->hvm = Tag_val(Field(v, 7)) == 0;
        infopriv = Field(Field(v, 7), 0);
        if (c_val->hvm) {
@@ -136,7 +136,7 @@ static int domain_build_info_val (libxl_domain_build_info *c_val, value v)
        } else {
                c_val->u.pv.slack_memkb = Int64_val(Field(infopriv, 0));
                c_val->u.pv.cmdline = String_val(Field(infopriv, 1));
-               c_val->u.pv.ramdisk = String_val(Field(infopriv, 2));
+               c_val->u.pv.ramdisk.path = String_val(Field(infopriv, 2));
                c_val->u.pv.features = String_val(Field(infopriv, 3));
        }